import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';

import '../services/shared_util.service.dart';

/// Async method used to search data with [query].
typedef StartSearch = Future<List<dynamic>> Function(String query);

/// Builds item for suggestion/result panel. It will be warpped with a [ListTile] automatically.
/// It typically can be [Column], [Row], [Container] and other widgets but NOT [ListTile].
typedef BuildSuggestionResultItem = Widget Function(dynamic entry);

/// Search delegate for general purpose. The return result is [dynamic] entry of parameter in [buildSuggestionItem] and [buildResultItem].
///
/// [buildSuggestionItem] is called every time [query] changes.
/// [buildResultItem] is called when search button pressed on keyboard.
///
/// Normally, user should tap on an item in suggestions or result to return.
/// But when [allowReturnQuery] is [true] user can return [query] directly without tapping on any item.
/// The default value is [false].
///
/// Example:
/// onTap: () async {
/// final result = await showSearch<dynamic>(
///   context: context,
///   delegate: GeneralSearchDelegate(
/// 	      UserService().queryAccountGroupUsersForTesting,
/// 	      buildSuggestionItem: (entry) {
/// 	    if (entry is User) {
/// 	      return Text(entry.fullName);
/// 	    }
///
/// 	    return Container();
/// 	  }),
/// 	);
///
/// 	print('Selected with $result');
/// },
class GeneralSearchDelegate extends SearchDelegate<dynamic> {
  GeneralSearchDelegate(
    this.startSearch, {
    super.searchFieldStyle = const TextStyle(fontSize: 16.0),
    this.buildSuggestionItem,
    this.buildResultItem,
    this.allowReturnQuery = false,
  }) : assert(buildSuggestionItem != null || buildResultItem != null);

  StartSearch startSearch;
  bool allowReturnQuery;
  BuildSuggestionResultItem? buildSuggestionItem;
  BuildSuggestionResultItem? buildResultItem;

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      icon: const Icon(Icons.arrow_back),
      onPressed: () => close(context, null),
    );
  }

  /// This is called every time [query] changes.
  @override
  Widget buildSuggestions(BuildContext context) {
    // Only displays [PagingListView] when [buildItem] is defined and [query] is not empty.
    if (buildSuggestionItem != null && !SharedUtil.checkNullOrEmpty(query)) {
      return _buildListView(buildSuggestionItem!);
    } else {
      return Container();
    }
  }

  /// This is called when search button pressed on keyboard.
  @override
  Widget buildResults(BuildContext context) {
    // We cannot leave result panel as empty. That's why we take [buildSuggestionItem] as long as [buildResultItem] is null.
    final buildItem = buildResultItem ?? buildSuggestionItem;

    // Only displays [PagingListView] when [buildItem] is defined and [query] is not empty.
    if (buildItem != null && !SharedUtil.checkNullOrEmpty(query)) {
      return _buildListView(buildItem);
    } else {
      return Container();
    }
  }

  @override
  List<Widget> buildActions(BuildContext context) {
    return [
      IconButton(
        icon: const Icon(Icons.clear),
        onPressed: () => query = '',
      ),
      if (allowReturnQuery)
        IconButton(
          icon: const Icon(Icons.done),
          onPressed: () => close(context, query),
        ),
    ];
  }

  /// Builds ListView with ListTile to display the suggestions/results.
  Widget _buildListView(BuildSuggestionResultItem buildItem) {
    return FutureBuilder<List<dynamic>>(
      future: startSearch(query),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          if (snapshot.data!.isEmpty) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Icon(
                  MdiIcons.noteSearchOutline,
                  size: 50.0,
                  color: Colors.grey,
                ),
                const Text(
                  '没有匹配',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontSize: 16.0,
                    color: Colors.grey,
                  ),
                ),
              ],
            );
          }

          return ListView(
            children: snapshot.data!
                .map((p) => ListTile(
                      title: buildItem(p),
                      onTap: () => close(context, p),
                    ))
                .toList(),
          );
        } else {
          return Center(child: Icon(MdiIcons.loading));
        }
      },
    );
  }
}
